<?php
class Util 
{
	const ENCODING_GBK  = 'GBK';
	const ENCODING_UTF8 = 'UTF-8';
    const ARRAY_WALK_RECURSIVE = 5;
    const CURL_TIMEOUT  = 1;

	public static function curl($url, $param = array(), $method = 'post', $options = array()) 
	{
		$ret               = array();
		$ret['info']  = NULL;
		$ret['result']     = NULL;

		if (!$url)
		{
			return $ret;
		}

		//set default value to curl options
		$timeout    = isset($options['timeout']) ? $options['timeout'] : self::CURL_TIMEOUT;
        $httpheader = isset($options['httpheader']) ? $options['httpheader'] : NULL;

		$ch = curl_init();

		curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);

		if ($httpheader)
		{
			curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
		}

        unset($options["timeout"], $options["httpheader"]);
        if ($options)
        {
            curl_setopt_array($ch, $options);
        }

		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

		//set to post
		if ('post' == strtolower($method)) 
		{
			curl_setopt($ch, CURLOPT_POST, 1);
			if ($param)
			{
				if (is_array($param))
				{
					curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($param));
				}
				else
				{
					curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
				}
            } 
            else 
            {
				curl_setopt($ch, CURLOPT_POSTFIELDS, "");
			}
		} 
		else if ($param) 
		{
			$url .= "?".http_build_query($param);
		}

		curl_setopt($ch, CURLOPT_URL, $url);
		$result          = curl_exec($ch);
		$ret['info'] = curl_getinfo($ch);
		$ret['result']   = $result;

		if (!$result)
		{
			$ret["error"]['message'] = curl_error($ch);
			$ret["error"]['code']    = curl_errno($ch);
		}
		
		$ret['url'] = $url;
		curl_close($ch);

		return $ret;
	}
	
	
	public static function buildHttpQuery($param, $urlencode = false, $separator = "&") 
	{
		if ($urlencode) 
		{
			return http_build_query($param);
		} 
		else 
		{
			$query_str = "";
			foreach($param as $key => $value) 
			{
				$query_str .= $key."=".$value.$separator;
			}

			if ($query_str) 
			{
				$query_str = substr($query_str, 0, strlen($query_str) - strlen($separator));
			}

			return $query_str;
		}	
	}

	public static function convertJsonToArray($json)
	{
		$arr = array();
		if (!$json || (!is_object($json) && !is_array($json))) 
		{
			return $arr;
		}			
		
		foreach($json as $k => $w)
		{
			if(is_array($w))
			{
				$arr[$k] = self::jsonToArray($w); 
			} 
			else if (is_object($w)) 
			{
				$w = (array)$w;
				$arr[$k] = self::jsonToArray($w);
			} 
			else 
			{
				$arr[$k] = $w;
			}
		}

		return $arr;
	}

    public static function diffMicroTime($start_microtime, $stop_microtime)
    {
        $slice_start = explode(" ", $start_microtime);
        $slice_stop  = explode(" ", $stop_microtime);


        $start_float = (float)$slice_start[0] + (float)$slice_start[1];
        $stop_float = (float)$slice_stop[0] + (float)$slice_stop[1];

        return $stop_float - $start_float;

    }
	public static function addUrlSchema($url) 
	{
		return self::addURLProtocol($url);
	}
	
	//strip http，https protocol in url 
	public static function addURLProtocol($url) 
	{
		if (!$url) {
			return $url;
		}
		if (false === strpos($url, 'http')) 
		{
			$url = "http://".$url;
		} 
		
		return $url;
	}

	public static function getUserIp($allowed_ip_segment = NULL, $allow_private = false)
	{
		//$ret      = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : NULL;
        $ret = NULL;
		$fallback = NULL;
		$fallback_ip_pattern = array();//i.e.'10.12';//allowed safe ips , array("10.249", "240.118")

        if ($allowed_ip_segment)
        {
            if (!is_array($allowed_ip_segment))
            {
                $fallback_ip_pattern = array($allowed_ip_segment);
            }
            else
            {
                $fallback_ip_pattern = $allowed_ip_segment;
            }
        }

		$ips = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']) : array();

		if(isset($_SERVER['REMOTE_ADDR'])) 
		{
			$ips[] = $_SERVER['REMOTE_ADDR'];
		}

		if(isset($_SERVER['HTTP_CLIENT_IP'])) 
		{
			$ips[] = $_SERVER["HTTP_CLIENT_IP"];
		}

		foreach ($ips as $ip)
		{
			if (!preg_match("/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/", $ip)) 
			{
				continue;
			}
			else if (!preg_match('/^10\.|^127\.|^172\.(?:1[6-9])\.|^192\.168\./', $ip)) //exclude private ip,|^224\.|^240\.
			{
				if (ip2long($ip) != false) 
				{
					$ret = $ip;
					break;
				}
			}
			else if($fallback_ip_pattern)
			{
				foreach ($fallback_ip_pattern as $pattern)
				{
					if(strncmp($ip, $pattern, strlen($pattern)) === 0)
					{
						if (ip2long($ip) != false)
						{
							$fallback = $ip;
							break;
						}
					}
				}
			}
            else if (preg_match('/^10\.|^127\.|^172\.(?:1[6-9])\.|^192\.168\./', $ip) && $allow_private)
            {
                $ret = $ip;
                break;
            }
		} //end foreach

		if ($ret === NULL) 
		{
			$ret = $fallback;
		}

		return $ret;
	}

	public static function writeFile($filename, $content = NULL, $type = "ab+")
	{
		if (!$filename)
		{
			return false;
		}

		$handle = @fopen($filename, $type);
		if($handle)
		{
            flock($handle, LOCK_EX);
			fwrite($handle, $content);
            flock($handle, LOCK_UN);
			fclose($handle);
			return true;
		}
		else 
		{
			error_log('write file '.$filename.' fail');
            error_log($content);
			return false;
		}
	}
	
	public static function redirect($new_url, $use_301 = true) 
	{
		while(@ob_end_clean());

		if ($use_301) 
		{
			 header( "HTTP/1.1 301 Moved Permanently" );
		}

		header('Location: '.$new_url);
	}


    public static function getDirFiles($dir, $type = "file")
    {
        $ret = array();

        if (!is_dir($dir))
        {
            return $ret;
        }

        if ($handle = opendir($dir)) 
        {
            while (false !== ($file = readdir($handle)))
            {
                if ('.' == $file || '..' == $file)
                {
                    continue;
                }

                $file = $dir.DIRECTORY_SEPARATOR.$file;
                if (is_file($file))
                {
                    if ("file" == $type)
                    {
                        $ret[] = $file;
                    }
                }
                else if (is_dir($file))
                {
                    if ("dir" == $type)
                    {
                        $ret[] = $file;
                    }
                }
            }

            closedir($handle);
        }

        return $ret;
    }

    /**
     * @param string $path
     * @param string $type, value is file or dir,or both
     */
    public static function getRecursiveDirFiles($path, $type = "file")
    {
        $ret = array();
        $ret = array();

        if ($handle = opendir($path)) 
        {
            while (false !== ($file = readdir($handle)))
            {

                if ('.' == $file || '..' == $file)
                {
                    continue;
                }

                $file = $dir.DIRECTORY_SEPARATOR.$file;

                if (is_file($file))
                {
                    if ("file" == $type)
                    {
                        $ret[] = $file;
                    }
                }
                else if (is_dir($file))
                {
                    $subdir     = self::getRecursiveDirFiles($file, $type);
                    if ("dir" == $type)
                    {
                        $ret[] = $file;
                        $ret   = array_merge($ret, $subdir);
                    }

                }
            }

            closedir($handle);
        }

        return $ret;
    }

	public static function isNumber($num) 
	{ 
		return  (preg_match("/^[-+]?[0-9]+$/", $num)) ?  TRUE : FALSE; 
	}

	public static function absCrc3264Bit($str)
	{
	   $crc = abs(crc32($str));

	   if( $crc & 0x80000000)
	   {
		  $crc ^= 0xffffffff;
		  $crc += 1;
	   }

	   return $crc;
	}

	//get string encoding
    public static function getStringEncoding($str)
    {
        for($i = 0; $i < strlen($str); $i++) 
		{
            $v = ord($str[$i]);
            if($v > 127) 
			{
                if(($v >= 228) && ($v <= 233))
                {
                    if(($i + 2) >= (strlen($str) - 1)) 
					{
						return self::ENCODING_GBK; 
					}

                    $v1 = ord( $str[$i + 1] );
                    $v2 = ord( $str[$i + 2] );

                    if(($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191))
					{
                        return self::ENCODING_UTF8;
					}
                    else
					{
                        return self::ENCODING_GBK; 
					}
                }
            }
        }

        return self::ENCODING_GBK; 
    }

	public static function isUTF8Encoding($word)
	{
		 if(preg_match("/^([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){1}/", $word) == true 
			 || preg_match("/([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){1}$/", $word) == true 
			 || preg_match("/([".chr(228)."-".chr(233)."]{1}[".chr(128)."-".chr(191)."]{1}[".chr(128)."-".chr(191)."]{1}){2,}/", $word) == true) 
		 {
			return true;
		 }
		 else 
		 {
			return false;
		 }
	}

	public static function isGBK($s)
	{
		//return self::ENCODING_GBK == self::getStringEncoding($s) ? true : false;
		return self::isUTF8Encoding($s) ? false : true;
	}

	public static function isUFT8($s)
	{
		//return self::ENCODING_UTF8 == self::getStringEncoding($s) ? true : false;
		return self::isUTF8Encoding($s) ? true : false;
	}

	//equivalent to python __NAME__ == __MAIN__
	public static function isMain()
	{
		return realpath(__FILE__) == realpath($_SERVER['SCRIPT_FILENAME']) ? true : false;
	}

	public static function getCaller($ignore = '/^Util/i') 
	{
		$caller = null;
		$i = 0;
        $count = count(debug_backtrace());

		foreach (debug_backtrace() as $v) 
		{
			if (1 == $i++)
            {
				$caller = $v;
				continue;
			}

			if (isset($v['object'])) 
			{
				$name = get_class($v['object']);
			} 
			elseif (isset($v['class'])) 
			{
				$name = $v['class'];
			} 
			else 
			{
				$name = '';
			}

			if (isset($v['function'])) 
			{
			  $name = ($name ? "$name#" : $name).$v['function'];
			}

			if (!preg_match($ignore, $name)) 
			{
				if (isset($caller['file'], $caller['line'])) 
			    {
					return "[CallBy ".$name." file ".$caller['file']." line ".$caller['line']."]";
			    }

			    return "[CallBy ".$name."]";
			}

			$caller = $v;
		} //end foreach

		return '[CallBy unknown]';
	}

	public static function loadTimeParam($prefix = '', $default = "") 
	{
		$time = array();
		$data = array();
		$param_name_start = 'start_time';
		$param_name_stop  = 'stop_time';

		if ($prefix) 
		{
			$param_name_start = $prefix.'_start_time';
			$param_name_stop = $prefix.'_stop_time';
		}

		if (isset($_GET[$param_name_start])) 
		{
			//$time[$param_name_start] = $_GET[$param_name_start];
			$time[$param_name_start] = NICED_Request::loadParamFromVar($param_name_start, NULL, "safe", "REQUEST", true);
		}
		if (!isset($time[$param_name_start]) && isset($_POST[$param_name_start])) 
		{
			//$time[$param_name_start] = $_POST[$param_name_start];
			$time[$param_name_start] = NICED_Request::loadParamFromVar($param_name_start, NULL, "safe", "REQUEST", true);
		}
		if (isset($_GET[$param_name_stop])) 
		{
			//$time[$param_name_stop] = $_GET[$param_name_stop];
			$time[$param_name_stop] = NICED_Request::loadParamFromVar($param_name_stop, NULL, "safe", "REQUEST", true);
		}
		if (!isset($time[$param_name_stop]) && isset($_POST[$param_name_stop])) 
		{
			//$time[$param_name_stop] = $_POST[$param_name_stop];
			$time[$param_name_stop] = NICED_Request::loadParamFromVar($param_name_stop, NULL, "safe", "REQUEST", true);
		}
		
		//default get current time
		$data[$param_name_start] = (isset($time[$param_name_start]) && $time[$param_name_start]) ? strtotime(trim($time[$param_name_start])) : $default;
		$data[$param_name_stop]  = (isset($time[$param_name_stop]) && $time[$param_name_stop]) ? strtotime(trim($time[$param_name_stop])) : $default;

		if ($data[$param_name_stop])//to yy-mm-dd 23:59:59
		{
			$data[$param_name_stop] += 60*60*24*1-1;
		}
		
		return $data;
	}

    public static function jsonEncode($arr)
    {
        return urldecode(json_encode(self::array_walk_recursive($arr, array("Util", "urlencoding"))));
    }

    public static function urlencoding(&$value, &$key, $userdata = "") 
    {
        $key   = urlencode($key);
        $value = urlencode($value);
    }

    /**
     * $arr = array("北京" => "哈哈");
     * Util::array_walk_recursive($arr, array("Util", "urlencoding"));
     * var_dump($arr);
     **/

    public static function array_walk_recursive(&$input, $funcname, $userdata = "", $level = 0) 
    {
        $output = array();
        if ($level > self::ARRAY_WALK_RECURSIVE)
        {
            error_log("array walk recursive level is too many");
            return $output;
        }

        if (!is_array($input)) 
        {
            return false;
        }

        $level++;
        foreach ($input as $key => $value) 
        {
            if (is_array($input[$key])) 
            {
                $temp = self::array_walk_recursive($input[$key], $funcname, $userdata, $level);
                foreach ($temp as $k => $v)
                {
                    $output[$key][$k] = $v;
                }            
            } 
            else 
            {
                $saved_value = $value;
                $saved_key = $key;
                if (!empty($userdata)) 
                {
                    if (is_array($funcname))
                    {
                        $classname = $funcname[0];
                        $funname   = $funcname[1];
                        eval($classname.'::'.$funname.'($value, $key, $userdata);');
                    }
                    else
                    {
                        $funcname($value, $key, $userdata);
                    }
                }
                else 
                {
                    if (is_array($funcname))
                    {
                        $classname = $funcname[0];
                        $funname   = $funcname[1];
                        eval($classname.'::'.$funname.'($value, $key);');
                    }
                    else
                    {
                        $funcname($value, $key);
                    }
                }

                $output[$key] = $value;
            }
        }

        return $output;
    }
} //end class

